package com.atguigu.gmall.cart.service.impl;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.util.unit.DataUnit;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 添加购物车
     * @param skuId
     * @param userId
     * @param skuNum
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addToCart(Long skuId, String userId, Integer skuNum) {

         /*
            1.  添加商品之前，先看一下购物车中是否有该商品
                true:
                    商品数量相加
                false:
                    直接加入购物车
            2.    将数据同步到redis！

         */
        //获取缓存的key
        String cartKey = this.getCartKey(userId);
        if (!redisTemplate.hasKey(cartKey)){
            //将数据库中的数据放入缓存
            this.loadCartCache(userId);
        }

        //select * from cart_info where skuId = ? and userId = ?;

//        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
//        wrapper.eq("user_id",userId);
//        wrapper.eq("sku_id",skuId);
//        CartInfo cartInfo = cartInfoMapper.selectOne(wrapper);
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartKey, skuId.toString());
        if (cartInfo!=null){
            //  说明购物车中已经有该商品了！
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            //  查询一下实时价格 skuInfo.price
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));

            cartInfo.setIsChecked(1);

            cartInfo.setUpdateTime(new Timestamp(new Date().getTime()));

            cartInfoMapper.updateById(cartInfo);
        }else {
            //购物车中不存在商品
            CartInfo cartNewInfo = new CartInfo();
            //  给cartInfo 赋值！
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);

            //  给表的字段赋值！
            cartNewInfo.setUserId(userId);
            cartNewInfo.setSkuId(skuId);
            cartNewInfo.setCartPrice(skuInfo.getPrice());
            cartNewInfo.setSkuNum(skuNum);
            cartNewInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartNewInfo.setSkuName(skuInfo.getSkuName());
            //Timestamp时间戳
            cartNewInfo.setCreateTime(new Timestamp(new Date().getTime()));
            cartNewInfo.setUpdateTime(new Timestamp(new Date().getTime()));

            //  非表的字段！
            cartNewInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            //  直接插入数据库！
            cartInfoMapper.insert(cartNewInfo);

            //  操作缓存！ cartInfo
            //  废物利用！
            cartInfo = cartNewInfo;
        }
        //Hash : key ,field,value   field最重要的目的
//        String cartKey = getCartKey(userId);
        redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfo);

        //  可以给购物车设置过期时间！
        setCartKeyExpire(cartKey);
    }

    /**
     * 通过用户Id 查询购物车列表
     * @param userId
     * @param userTempId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<CartInfo> getCartList(String userId, String userTempId) {

        List<CartInfo> cartInfoList = new ArrayList<>();
        //未登录，没有用户id
        if (StringUtils.isEmpty(userId)){
            cartInfoList = this.getCartList(userTempId);
        }
        /*
         1. 准备合并购物车
         2. 获取未登录的购物车数据
         3. 如果未登录购物车中有数据，则进行合并 合并的条件：skuId 相同 则数量相加，合并完成之后，删除未登录的数据！
         4. 如果未登录购物车没有数据，则直接显示已登录的数据
          */

        if (!StringUtils.isEmpty(userId)){
            if (StringUtils.isEmpty(userTempId)) {
                //如果临时用户id为空的话，直接返回用户购物车
                cartInfoList = this.getCartList(userId);
                return cartInfoList;
            }
        }
        //已登录
        if (!StringUtils.isEmpty(userId)) {
            //先获取未登录的数据
            List<CartInfo> noLoginCartList = this.getCartList(userTempId);
            if (!CollectionUtils.isEmpty(noLoginCartList)){
                cartInfoList = this.mergeToCartList(noLoginCartList, userId);
                // 删除未登录购物车数据
                this.deleteCartList(userTempId);
            }
        }else {
            //  只有登录的购物车数据
            cartInfoList = this.getCartList(userId);
        }
        return cartInfoList;
    }

    /**
     * 选中状态变更
     * @param userId
     * @param isChecked
     * @param skuId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkCart(String userId, Integer isChecked, Long skuId) {
        CartInfo cartInfoUpd = new CartInfo();
                    cartInfoUpd.setIsChecked(isChecked);
                    UpdateWrapper<CartInfo> cartInfoUpdateWrapper = new UpdateWrapper<>();
                    cartInfoUpdateWrapper.eq("sku_id",skuId);
                    cartInfoUpdateWrapper.eq("user_id",userId);
                    cartInfoMapper.update(cartInfoUpd,cartInfoUpdateWrapper);
        String cartKey = this.getCartKey(userId);

        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartKey, skuId.toString());
//        cartInfoMapper.updateById(cartInfo);

        if (cartInfo!=null){
            cartInfo.setIsChecked(isChecked);
            redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfo);
        }

    }

    /**
     * 删除购物车中数据
     * @param userId
     * @param skuId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCartInfo(String userId, Long skuId) {

        cartInfoMapper.delete(new QueryWrapper<CartInfo>().eq("user_id",userId).eq("sku_id",skuId));

        String cartKey = this.getCartKey(userId);
        Boolean hasKey = redisTemplate.boundHashOps(cartKey).hasKey(skuId.toString());
        if(hasKey){
            redisTemplate.boundHashOps(cartKey).delete(skuId.toString());
        }
    }

    /**
     * 删除未登录购物车数据
     * @param userTempId
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteCartList(String userTempId) {
        cartInfoMapper.delete(new QueryWrapper<CartInfo>().eq("user_id",userTempId));

        String cartKey = this.getCartKey(userTempId);

        Boolean hasKey = redisTemplate.hasKey(cartKey);
        if (hasKey){
            redisTemplate.delete(cartKey);
        }
    }

    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        List<CartInfo> cartInfos = new ArrayList<>();
        String cartKey = this.getCartKey(userId);
        List<CartInfo> values = redisTemplate.boundHashOps(cartKey).values();
        if (values!=null&&values.size()>0){
            for (CartInfo value : values) {
                if (value.getIsChecked()==1) {
                    cartInfos.add(value);
                }
            }
        }


        return cartInfos;
    }

    /**
     * 合并购物车数据集合
     * @param noLoginCartList   未登录购物车集合
     * @param userId    通过userId 查询到登录的购物车集合
     * @return
     */
    private List<CartInfo> mergeToCartList(List<CartInfo> noLoginCartList, String userId) {
        //  声明一个购物车集合对象
        List<CartInfo> cartInfoList = new ArrayList<>();

        List<CartInfo> loginCartList = this.getCartList(userId);
        Map<Long, CartInfo> longCartInfoMap = loginCartList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
        for (CartInfo noLoginCartInfo : noLoginCartList) {
            if (longCartInfoMap.containsKey(noLoginCartInfo.getSkuId())){
                CartInfo logInCartInfo = longCartInfoMap.get(noLoginCartInfo.getSkuId());
                logInCartInfo.setSkuNum(logInCartInfo.getSkuNum()+noLoginCartInfo.getSkuNum());
                logInCartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
                //  细节处理： 选中状态处理
                if (noLoginCartInfo.getIsChecked().intValue()==1){
                    logInCartInfo.setIsChecked(1);
                }
                //  执行更新语句！
                cartInfoMapper.updateById(logInCartInfo);
            }else {
                noLoginCartInfo.setUserId(userId);
                noLoginCartInfo.setCreateTime(new Timestamp(new Date().getTime()));
                noLoginCartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
                cartInfoMapper.insert(noLoginCartInfo);
            }
        }
        //汇总所有的登录状态下的集合
        cartInfoList = loadCartCache(userId);
        return cartInfoList;
    }

    /**
     * 根据用户获取购物车，方法重载，名相同，参数不同
     * @param userId
     * @return
     */
    private List<CartInfo> getCartList(String userId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
        if (StringUtils.isEmpty(userId)){
            return cartInfoList;
        }
        /*
        1.  根据用户Id 查询 {先查询缓存，缓存没有，再查询数据库}
         */
        String cartKey = this.getCartKey(userId);
//        cartInfoList = redisTemplate.boundHashOps(cartKey).values();和下一条数据效果一样
        cartInfoList = redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(cartInfoList)){
            cartInfoList.sort((o1,o2)->{
                return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
            });
        }else {
            // 缓存中没用数据！查询数据库
            cartInfoList = loadCartCache(userId);

        }
        return cartInfoList;
    }

    /**
     * 从数据库拿取数据
     * @param userId
     * @return
     */
    public List<CartInfo> loadCartCache(String userId) {
        QueryWrapper queryWrapper = new QueryWrapper<CartInfo>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.orderByDesc("update_time");
        List<CartInfo> cartInfoList = cartInfoMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(cartInfoList)) {
            return cartInfoList;
        }
        String cartKey = this.getCartKey(userId);
        HashMap<String, CartInfo> map = new HashMap<>();
        for (CartInfo cartInfo : cartInfoList) {
            BigDecimal skuPrice = productFeignClient.getSkuPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(skuPrice);
            map.put(cartInfo.getSkuId().toString(), cartInfo);
        }

        // 将数据库中的数据查询并放入缓存
        redisTemplate.opsForHash().putAll(cartKey,map);
        // 设置过期时间
        this.setCartKeyExpire(cartKey);

        return cartInfoList;
    }

    /**
         * 购物车设置过期时间！
         * @param cartKey
         */
    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }

    //  获取购物车的key
    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
    }
}
